package com.cloudkinto.service.finance.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.DicBusinessItemConstant;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.utils.TimeUtils;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.*;
import com.cloudkinto.extentity.CompanyAccountDto;
import com.cloudkinto.service.finance.CompanyAccountService;
import com.cloudkinto.service.finance.CompanyBillNoteService;
import com.cloudkinto.service.finance.CostRecordService;
import com.cloudkinto.service.finance.vo.CompanyAccountPageRes;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author ding
 * @since 2020-06-10
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class CompanyAccountServiceImpl extends ServiceImpl<CompanyAccountDao, CompanyAccountDo> implements CompanyAccountService {
    @Autowired
    private CompanyAccountDao dao;
    @Autowired
    private CompanyBillNoteService billNoteService;
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private RechargeRecordDao rechargeDao;
    @Autowired
    private CostRecordDao costRecordDao;
    @Autowired
    private CostRecordService costRecordService;
    @Autowired
    private ExchangeRateDao exchangeRateDao;

    @Override
    public SingleResult addInit() {
        return SingleResult.success("");
    }

    @Override
    public Object add(Object req, Long userId) {
        CompanyAccountDo entityDo = new CompanyAccountDo();
        BeanUtils.copyProperties(req, entityDo);
        handlerAddBefore(entityDo, userId);
        dao.insert(entityDo);
        return handlerAddAfter(entityDo);
    }

    @Override
    public Double addAmount(RechargeRecordDo recordDo) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("company_id", recordDo.getCompanyId());
        CompanyAccountDo accountDo = dao.selectOne(wrapper);
        if (accountDo == null) {
            accountDo = new CompanyAccountDo();
//            if (recordDo.getRechargeAccount() == 0L) {
            //充值人民币账户
//                accountDo.setCompanyAccountRmb(recordDo.getAmountRmb());
//            } else {
            accountDo.setCompanyAccount(recordDo.getAmountJpy());
//            }
            accountDo.setCompanyId(recordDo.getCompanyId());
//            accountDo.setCreateBy(req.getCreateBy());
            accountDo.setCreateTime(new Date());
            accountDo.setCreditPoints(0);
        } else {
//            if (recordDo.getRechargeAccount() == 0L) {//充值人民币账户
//                accountDo.setCompanyAccountRmb(accountDo.getCompanyAccountRmb() + recordDo.getAmountRmb());
//            } else {//充值日币账户
            accountDo.setCompanyAccount(accountDo.getCompanyAccount() + recordDo.getAmountJpy());
//            }
            accountDo.setUpdateTime(new Date());
        }
        accountDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
        accountDo.setCreateBy(recordDo.getCreateBy());
        saveOrUpdate(accountDo);
        return accountDo.getCompanyAccount();
    }

    //新增校验
    private void addCheck(RechargeRecordDo req) {

    }

    //做新增之前要执行的业务定制处理
    private void handlerAddBefore(CompanyAccountDo entityDo, Long userId) {
        entityDo.setCreateBy(userId);
        entityDo.setCreateTime(new Date());
        entityDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
    }

    //将新增的do转换成要返回的实体
    private Object handlerAddAfter(CompanyAccountDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public SingleResult updateInit(Long id) {
        return SingleResult.success("");
    }

    @Override
    public Object update(Object req, Long userId) {
        /*CompanyAccountDo entityDo = dao.selectById(req.getId());
        BeanUtils.copyProperties(req, entityDo);
        handlerUpdateBefore(entityDo, userId);
        dao.updateById(entityDo);
        return handlerUpdateAfter(entityDo);*/
        return null;
    }

    //编辑校验
    private void updateCheck(Object req) {

    }

    //做修改之前要执行的业务定制处理
    private void handlerUpdateBefore(CompanyAccountDo entityDo, Long userId) {
        entityDo.setUpdateBy(userId);
        entityDo.setUpdateTime(new Date());
    }

    //做修改之后要执行的业务定制处理
    private Object handlerUpdateAfter(CompanyAccountDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public int delete(Long id, Long userId) {
        CompanyAccountDo entityDo = dao.selectById(id);
        handlerDeleteBefore(entityDo, userId);
        return dao.deleteById(id);
    }

    //做删除之前要执行的业务定制处理
    private void handlerDeleteBefore(CompanyAccountDo entityDo, Long userId) {
//        entityDo.setDeleteBy(userId);
//        entityDo.setDeleteTime(new Date());
    }

    @Override
    public Object detail(Long id) {
        CompanyAccountDo entityDo = dao.selectById(id);
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return handlerDetailAfter(res);
    }

    //查询明细之后要执行的业务定制处理
    private Object handlerDetailAfter(Object res) {
        return res;
    }

    @Override
    public SingleResult pageInit() {
        return SingleResult.success("");
    }

    @Override
    public List<CompanyAccountPageRes> getList(Map<String, String> map) {
        QueryWrapper<CompanyAccountDo> wrapper = queryBuild(map);
        List<CompanyAccountDo> list = this.list(wrapper);
        List<CompanyAccountPageRes> result = handlerListAfter(map, list);
        return result;
    }

    @Override
    public PageResult getListPage(Map<String, String> map) {
        Date startDate = TimeUtils.parseDate(map.get("startDate") != null ? map.get("startDate") : "2020-01-01");
        Date endDate = TimeUtils.parseDate(map.get("endDate") != null ?  TimeUtils.addDaysFormat(map.get("endDate"), "yyyy-MM-dd", 1) : TimeUtils.getCurrentDateFormat(1));
//        IPage<CompanyAccountDto> page = pageInitDto(map);
//        List<CompanyAccountDto> resList = dao.getAccountDetails(page, startDate, endDate, map);
//        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());

        int currentPage = org.apache.commons.lang3.StringUtils.isNotBlank(map.get("current")) ? Integer.parseInt(map.get("current")) : 10;
        PageHelper.startPage(currentPage, org.apache.commons.lang3.StringUtils.isNotBlank(map.get("pageSize")) ? Integer.parseInt(map.get("pageSize")) : 10);
        List<CompanyAccountDto> resList = dao.getAccountDetails( startDate, endDate, map);
        PageInfo<CompanyAccountDto> pageInfo = new PageInfo<>(resList);
        PageResult result = new PageResult(resList, currentPage, pageInfo.getPageSize(), (int) pageInfo.getTotal(), pageInfo.getPages());
        return result;
    }

    //查询分页列表之后对列表数据的处理
    private List<CompanyAccountPageRes> handlerListAfter(Map<String, String> map, List<CompanyAccountDo> list) {
        Date startDate = TimeUtils.parseDate(map.get("startDate") != null ? map.get("startDate") : "2020-01-01");
        Date endDate = TimeUtils.parseDate(map.get("endDate") != null ? map.get("endDate") : TimeUtils.getCurrentDateFormat(1));
        List<CompanyAccountPageRes> result = new ArrayList<>();
        list.stream().forEach(companyAccountDo -> {
            CompanyAccountPageRes res = new CompanyAccountPageRes();
            CompanyDo companyDo = companyDao.selectById(companyAccountDo.getCompanyId());
            List<RechargeRecordDo> rechargeRecordDoList = rechargeDao.getRechargeList(companyAccountDo.getCompanyId(), startDate, TimeUtils.getDateAdd(endDate, 1));
            List<CostRecordDo> costRecordDoList = costRecordDao.getCostList(companyAccountDo.getCompanyId(), startDate, TimeUtils.getDateAdd(endDate, 1));
            double rechargeJpy = rechargeRecordDoList.stream().filter(rechargeRecordDo -> rechargeRecordDo.getRechargeAccount() == null || rechargeRecordDo.getRechargeAccount() == 1L).mapToDouble(RechargeRecordDo::getAmountJpy).sum();
            double rechargeRmb = rechargeRecordDoList.stream().filter(rechargeRecordDo -> rechargeRecordDo.getRechargeAccount() != null && rechargeRecordDo.getRechargeAccount() == 0L).mapToDouble(RechargeRecordDo::getAmountRmb).sum();

            double costJpy = costRecordDoList.stream().filter(costRecordDo -> costRecordDo.getAccountType() == null || costRecordDo.getAccountType() == 1L).mapToDouble(CostRecordDo::getCostAmount).sum();
            double costRmb = costRecordDoList.stream().filter(costRecordDo -> costRecordDo.getAccountType() != null && costRecordDo.getAccountType() == 0L).mapToDouble(CostRecordDo::getCostAmount).sum();

            if (companyDo != null) {
                res.setCompanyCode(companyDo.getCompanyCode());
                res.setCompanyName(companyDo.getName());
            }
            res.setId(companyAccountDo.getId());
            //日币
            res.setBalanceJpy(companyAccountDo.getCompanyAccount());
            res.setRechargeAmountJpy(new BigDecimal(rechargeJpy).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            res.setCostAmountJpy(new BigDecimal(costJpy).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());

            //人民币
            res.setBalanceRmb(companyAccountDo.getCompanyAccountRmb());
            res.setRechargeAmountRmb(new BigDecimal(rechargeRmb).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            res.setCostAmountRmb(new BigDecimal(costRmb).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            result.add(res);
        });
        return result;
    }

    private IPage<CompanyAccountDo> pageInit(Map<String, String> map) {
        IPage<CompanyAccountDo> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }


    private IPage<CompanyAccountDto> pageInitDto(Map<String, String> map) {
        IPage<CompanyAccountDto> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    private QueryWrapper<CompanyAccountDo> queryBuild(Map<String, String> map) {
        QueryWrapper<CompanyAccountDo> wrapper1 = new QueryWrapper<>();

        if (StringUtils.isNotBlank(map.get("companyId"))) {
            wrapper1.eq("company_id", map.get("companyId"));
        } else {
            QueryWrapper<CompanyDo> wrapper = new QueryWrapper<>();
            if (StringUtils.isNotBlank(map.get("keyword"))) {
                String s = map.get("keyword").replaceAll(" ", "%")
                        .replaceAll("　", "%");
                wrapper.like("company_code",s).or(true).like("name", s);
            }
            List<CompanyDo> companyDos = companyDao.selectList(wrapper);
            List<Long> ids = companyDos.stream().map(CompanyDo::getId).collect(Collectors.toList());
            wrapper1.in("company_id", ids);
        }

        return wrapper1;
    }

    @Override
    public void countBillNote() {
        List<CompanyAccountDo> accountAmountList = list();
        for (CompanyAccountDo amount : accountAmountList) {
            if (amount.getCompanyAccount() >= 0 || amount.getDueFlag() == 0) continue;
            billNoteService.saveBillNote(amount.getCompanyId(), TimeUtils.getCurrentDateTimeFormat(), amount.getCompanyAccount(),
                    amount.getCompanyAccount(), TimeUtils.getLastMonthDate(), TimeUtils.getCurrentDateFormat("MM-dd"));
        }
    }

    @Override
    public boolean getIsDue(Long companyId) {
        boolean flag = false;
        LambdaQueryWrapper<CompanyAccountDo> wrapper1 = new LambdaQueryWrapper();
        wrapper1.eq(CompanyAccountDo::getCompanyId, companyId);
        CompanyAccountDo amount = baseMapper.selectOne(wrapper1);
        CompanyBillNoteDo billNote = billNoteService.queryLastByCompanyId(companyId);
        if (amount != null && amount.getCompanyAccount() >= -amount.getMaxLimit()) {
            if (billNote == null) {
                flag = true;//未欠款
            } else if (billNote.getClearFlag()) {
                flag = false;
            } else {
                flag = true;//未欠款
            }
        }
        return flag;
    }


    /**
     * 扣款
     *
     * @param companyId
     * @param costAmount
     * @param currency   0 扣人民币账户 1扣日币账户
     * @return 实际扣款账户
     */
    @Override
    public synchronized double costAmount(String companyId, Double costAmount, Integer currency) {
            LambdaQueryWrapper<CompanyAccountDo> wr = new LambdaQueryWrapper<>();
            wr.eq(CompanyAccountDo::getCompanyId, companyId);
            CompanyAccountDo amount = baseMapper.selectOne(wr);
            if (amount == null) {
                amount = new CompanyAccountDo();
                amount.setCompanyAccount(0D);
                amount.setCompanyAccountRmb(0D);
                amount.setCompanyId(Long.parseLong(companyId));
                amount.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
//            accountDo.setCreateBy(req.getCreateBy());
                amount.setCreateTime(new Date());
                amount.setCreditPoints(0);
                dao.insert(amount);
            }
//            amount.setCompanyAccount(amount.getCompanyAccount() - costAmount);
            dao.updateAmountById(amount.getId(), costAmount);
            amount = baseMapper.selectOne(wr);
            return amount.getCompanyAccount();
    }

    @Override
    public void updateAmount() {
//        ExchangeRateDo exchangeRateDo = getRate();
//        QueryWrapper wrapper = new QueryWrapper();
//        wrapper.eq("status", 0);
//        List<CostRecordDo> costRecords = costRecordDao.selectList(wrapper);
//        for (CostRecordDo record :
//                costRecords) {
//            LambdaQueryWrapper<CompanyAccountDo> wrapper1 = new LambdaQueryWrapper();
//            wrapper1.eq(CompanyAccountDo::getCompanyId, record.getCompanyId());
//            CompanyAccountDo amount = dao.selectOne(wrapper1);
//            amount.setCompanyAccount(amount.getCompanyAccount() - record.getCostAmount());
//            boolean b = updateById(amount);
//            if (b) {
//                record.setStatus(1);
//                costRecordDao.updateById(record);
//            }
//        }
//        List<CompanyAccountDo> companyAccountDoList = dao.selectList(null);
//        companyAccountDoList.stream()
//                .filter(companyAccountDo -> companyAccountDo.getCompanyAccountRmb() != 0)
//                .forEach(new Consumer<CompanyAccountDo>() {
//                    @Override
//                    public void accept(CompanyAccountDo companyAccountDo) {
//                        //人民币账户所欠，对应的日币金额
//                        double dueAmount = companyAccountDo.getCompanyAccountRmb() * 100 / exchangeRateDo.getRate();
//                        companyAccountDo.setCompanyAccountRmb(0D);
//                        companyAccountDo.setCompanyAccount(dueAmount + companyAccountDo.getCompanyAccount());
//                        costRecordService.addExchange(1, "换汇(" + exchangeRateDo.getRate() + ")", Math.abs(dueAmount), companyAccountDo.getCompanyAccount(), 0L, companyAccountDo.getCompanyId());
//                        updateById(comp anyAccountDo);
//                    }
//                });
    }

    private ExchangeRateDo getRate() {
        QueryWrapper exrateWrapper = new QueryWrapper();
        exrateWrapper.orderByDesc("id");
        exrateWrapper.eq("type", DicBusinessItemConstant.CurrencyTypeJpy);
        exrateWrapper.last("limit 1");
        ExchangeRateDo exchangeRate = exchangeRateDao.selectOne(exrateWrapper);
        return exchangeRate;
    }
}
